package com.landtool.Netty;

import com.landtool.utils.ZipUtil;
import com.landtool.controller.Shipping;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class WebSocketChannelHandler extends SimpleChannelInboundHandler <Object> {


    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketChannelHandler.class);

    private static final String URI = "websocket";

    private WebSocketServerHandshaker handshaker;


    /**
     * 连接上服务器
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        LOGGER.info("【handlerAdded】====>" + ctx.channel().id() + " : " + ctx.channel().remoteAddress().toString());
        GlobalUtil.channels.add(ctx.channel());
    }

    /**
     * 断开连接
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        LOGGER.info("【handlerRemoved】====>" + ctx.channel().id() + " : " + ctx.channel().remoteAddress().toString());
        GlobalUtil.channels.remove(ctx.channel());


    }

    /**
     * 连接异常，需要关闭相关资源
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        LOGGER.error("【系统异常】======>" + cause.toString());
        ctx.close();
        ctx.channel().close();
    }

    /**
     * 活跃的通道  也可以当作用户连接上客户端进行使用
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        LOGGER.info("【channelActive】=====>" + ctx.channel() + " : " + ctx.channel().remoteAddress().toString());
    }

    /**
     * 不活跃的通道  就说明用户失去连接
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        LOGGER.error("【用户失去连接】======>" + ctx.channel());
    }

    /**
     * 这里只要完成 flush
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        LOGGER.info("【完成推送】======>" + ctx.channel());
        ctx.flush();
    }

    /**
     * 这里是保持服务器与客户端长连接  进行心跳检测 避免连接断开
     */
//    @Override
//    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
//        if (evt instanceof IdleStateEvent) {
//            IdleStateEvent stateEvent = (IdleStateEvent) evt;
//            PingWebSocketFrame ping = new PingWebSocketFrame();
//            switch (stateEvent.state()) {
//                // 读空闲（服务器端）
//                case READER_IDLE:
//                    LOGGER.info("【" + ctx.channel().remoteAddress() + "】读空闲（服务器端）");
//                    ctx.writeAndFlush(ping);
//                    break;
//                // 写空闲（客户端）
//                case WRITER_IDLE:
//                    LOGGER.info("【" + ctx.channel().remoteAddress() + "】写空闲（客户端）");
//                    ctx.writeAndFlush(ping);
//                    break;
//                case ALL_IDLE:
//                    LOGGER.info("【" + ctx.channel().remoteAddress() + "】读写空闲");
//                    break;
//            }
//        }
//    }

    /**
     * 收发消息处理（重点）
     */
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof HttpRequest) {
            doHandlerHttpRequest(ctx, (HttpRequest) msg);
            // 发送连接成功给客户端
            ctx.channel().writeAndFlush(new TextWebSocketFrame(ZipUtil.gzip(Shipping.strCurMB)));
        } else if (msg instanceof WebSocketFrame) {
            doHandlerWebSocketFrame(ctx, (WebSocketFrame) msg);
        }
    }

    /**
     * websocket消息处理
     */
    private void doHandlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame msg) {
        // 判断msg 是哪一种类型  分别做出不同的反应

        // 判断是否是关闭链路的指令
        if (msg instanceof CloseWebSocketFrame) {
            System.out.println(1);
            handshaker.close(ctx.channel(), (CloseWebSocketFrame) msg.retain());
            return;
        }
        // 判断是否是Ping消息
        if (msg instanceof PingWebSocketFrame) {
            LOGGER.info("【ping】");
            PongWebSocketFrame pong = new PongWebSocketFrame(msg.content().retain());
//            ctx.channel().writeAndFlush(pong);
            return;
        }
//        // 判断是否是Pong消息
        if (msg instanceof PongWebSocketFrame) {
            LOGGER.info("【pong】");
            PingWebSocketFrame ping = new PingWebSocketFrame(msg.content().retain());
            return;
        }

        // 文本消息，不支持二进制消息
        if (msg instanceof TextWebSocketFrame) {
            // 返回应答消息
            String request = ((TextWebSocketFrame) msg).text();
            LOGGER.info("【requestMsg】====>" + request);
            String now = (new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")).format(Calendar.getInstance().getTime());
            ctx.channel().writeAndFlush(new TextWebSocketFrame("【message】 船只数据服务，不要给服务器发数据 【Now time】" + now));
            return;
        }
        //可以对消息进行处理
        LOGGER.info("【不支持二进制】");
        throw new UnsupportedOperationException("不支持二进制");

    }


    /**
     * wetsocket第一次连接握手
     */
    private void doHandlerHttpRequest(ChannelHandlerContext ctx, HttpRequest msg) {
        //http解码失败
        if (!msg.decoderResult().isSuccess() || (!"websocket".equalsIgnoreCase(msg.headers().get("Upgrade")))) {
            sendHttpResponse(ctx, (FullHttpRequest) msg, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
        }
        // 可以获取msg的uri来判断
        String uri = msg.uri();
        if (!uri.substring(1).equals(URI)) {
            ctx.close();
        }
        // 不知道干嘛的
        // ctx.attr(AttributeKey.valueOf("type")).set(uri);
        // 可以通过url获取其他参数
        WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory("ws://" + msg.headers().get("Host") + "/" + URI + "", null, false);
        handshaker = factory.newHandshaker(msg);
        if (handshaker == null) {
            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
        } else {
            handshaker.handshake(ctx.channel(), msg);
        }
        // 可以做其他处理
    }

    private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, DefaultFullHttpResponse res) {
        // 返回应答给客户端
        if (res.status() != HttpResponseStatus.OK) {
            ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
            res.content().writeBytes(buf);
            buf.release();
        }
        // 如果是非Keep-Alive，关闭连接
        ChannelFuture f = ctx.channel().writeAndFlush(res);
        if (!HttpUtil.isKeepAlive(req) || res.status() != HttpResponseStatus.OK) {
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }
}

